/* $Header: rs232task.c,v 2.7 20/3./7. 1.:2.:3. dryden Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991                 */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME: rs232task.c                                            */
/* ============                                                        */
/*                                                                     */
/* Author:  Bob Cook                                                   */
/*                                                                     */
/* MODULE PURPOSE: Background NewtOS task for RS232 host and           */
/*   diagnostic commands.                                              */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/


#include <typedefs.h>
#include <p_wkfile.h>
#include <wkfile.h>
#include <ramps.h>
#include <zone_config.h>
#include <config.h>
#include <zone_status.h>
#include <status.h>

#include <stddef.h>
#include <std_ops.h>
#include <task_pub.h>
#include <iomap.h>

#include <error.h>
#include <diag.h>
#include <i_op.h>


#include <method.h>

#include <mio.h>
#include <cmd_set.h>
#include <hostutil.h>
#include <cmdproc.h>
#include <duartchip.h>
#include <duart.h>

#include <exception.h>
#include <err_handler.h>


/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/


/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/


/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/

/********  MIO Read Packets *********/
extern QUEUE_TYPE  Rd_Input_Q;

extern QUEUE_TYPE  Rd_Free_Q;

/********  MIO write Packets *********/
extern QUEUE_TYPE  Wr_Output_Q[NUM_PORTS];
extern pthread_mutex_t Wr_Output_Q_Mut;

extern QUEUE_TYPE  Wr_Free_Q;
extern pthread_mutex_t Wr_Free_Q_Mut;

/*****************************/
/*   LOCAL DEFINES           */
/*****************************/

#define LAN_CONFIG_TIMEOUT 2560
#define Stx 2

/*****************************/
/*   STATIC VARIABLES        */
/*****************************/


/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/


const BIT8 UDS_LANTRONIX[] = "LANTRONIX";
const BIT8 UDS_SERIAL_NUMBER[] = "SERIAL NUMBER ";
const BIT8 UDS_MAC_ADDRESS[] = "MAC ADDRESS ";
const BIT8 UDS_SOFTWARE_VERSION[] = "SOFTWARE VERSION ";
const BIT8 UDS_SETUP_MODE[] = "PRESS ENTER TO GO INTO SETUP MODE";
const BIT8 UDS_YOUR_CHOICE[] = "YOUR CHOICE ?";
const BIT8 UDS_RIGHT_PAREN[] = ") ";
const BIT8 UDS_DEFAULT[] = "DEFAULT)";
const BIT8 UDS_COLON[] = ":";
const BIT8 UDS_Q_N[] = "? (N)";



/***********************************************************************/
/* FUNCTION: NextCharacter                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: wait for a character to be received from the Lantronix     */
/*          LAN card and return it, or time out and return null        */
/*                                                                     */
/* RETURNED VALUE: upshifted ASCII character or null                   */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

static BIT8 NextCharacter(void)
{
U_INT16  data_status;
BIT8     data;
DUARTBUF_RX_TYPE  *pduartRxbuf_v;

   pduartRxbuf_v = &DuartRxBuf_V[LAN_PORT];

   /* return only if a character was received or if timeout */
   while( Duart_CB[4].Handshake_Timeout < LAN_CONFIG_TIMEOUT )
   {

      /* see if any characters in the receive buffer */
      if( pduartRxbuf_v->count > 0 )
      {
         /* get one character from the buffer */
         INTERRUPTS_OFF;
            GetBufPtr(pduartRxbuf_v,&data_status);
         INTERRUPTS_ON;

         /* ignore any error bits */
         data = (BIT8)data_status;

         /* ignore the eighth data bit */
         data &= 0x7F;

         /* upshift lower case characters to corresponding upper case */
         if( (data >= 'a') && (data <= 'z') )
         {
            data -= ('a' - 'A');
         }

         /* this is the value returned if anything received */
         return data;
      }

      /* until something was received or we timed out, yield */
      Task_yield();
   }

   /* return null if nothing received before timeout */
   return (BIT8)0;
}

/***********************************************************************/
/* FUNCTION: ScanForString                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: wait until the specified string of characters has been     */
/*          received from the Lantronix LAN card or until time has     */
/*          run out                                                    */
/*                                                                     */
/* RETURNED VALUE: TRUE if the string was received, FALSE if timed out */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

static BIT8 ScanForString(const BIT8 *string)
{
const BIT8 *match;
BIT8 data;

   /* initially compare to first char in string constant */
   match = string;

   /* return only if found match to entire string, or timeout */
   while( Duart_CB[4].Handshake_Timeout < LAN_CONFIG_TIMEOUT)
   {
      if( *match == (BIT8)0 )
      {
         return TRUE;
      }
      /* get the next character */
      data = NextCharacter();
      if( *match == data )
      {
         match++;
      }
      else
      {
         match = string;
         if( *match == data )
         {
            match++;
         }
      }
   }
   return FALSE;
}

/***********************************************************************/
/* FUNCTION: ScanForTwoStrings                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: wait until one of two specified strings of characters      */
/*          has been received from the Lantronix LAN card or until     */
/*          time has run out                                           */
/*                                                                     */
/* RETURNED VALUE: 1 or 2 if one of the strings was received, 0 if     */
/*                 timed out                                           */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

static BIT8 ScanForTwoStrings(const BIT8 *string1, const BIT8 *string2)
{
const BIT8 *match1;
const BIT8 *match2;
BIT8 data;

   /* initially compare to first char in either string constant */
   match1 = string1;
   match2 = string2;

   /* return only if found match to entire string, or timeout */
   while( Duart_CB[4].Handshake_Timeout < LAN_CONFIG_TIMEOUT)
   {
      if( *match1 == (BIT8)0 )
      {
         return 1;
      }
      if( *match2 == (BIT8)0 )
      {
         return 2;
      }
      /* get the next character */
      data = NextCharacter();
      if( *match1 == data )
      {
         match1++;
      }
      else
      {
         match1 = string1;
         if( *match1 == data )
         {
            match1++;
         }
      }
      if( *match2 == data )
      {
         match2++;
      }
      else
      {
         match2 = string2;
         if( *match2 == data )
         {
            match2++;
         }
      }
   }
   return 0;
}

/***********************************************************************/
/* FUNCTION: SaveStringData                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: copy incoming characters until the specified character     */
/*          is received, or the specified number of characters have    */
/*          been received, or a non-printing character has             */
/*          been received, or time has run out                         */
/*                                                                     */
/* RETURNED VALUE: number of characters saved to memory                */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

static BIT8 SaveStringData(BIT8 *save, BIT8 match, BIT8 max)
{
BIT8 count;
BIT8 data;

   /* initialize return count */
   count = 0;
   *save = (BIT8)0;

   /* return if found specified char or specified number of char or timeout */
   while( Duart_CB[4].Handshake_Timeout < LAN_CONFIG_TIMEOUT)
   {

      /* see if we have saved the maximum number of characters */
      if( count >= max )
      {
         return count;
      }

      /* get the next character */
      data = NextCharacter();

      /* see if it is the specified terminating character */
      if( data == match )
      {
         return count;
      }

      /* see if it is a non-printing character */
      if( ( data < (BIT8)' ' ) || ( data > (BIT8)'z' ) )
      {
         return count;
      }

      /* if it is not the terminating character and there is */
      /* still room then save it */
      *save++ = data;
      count++;
      *save = (BIT8)0;
   }

   /* timed out, return how many characters we had already saved */
   return count;
}

/***********************************************************************/
/* FUNCTION: SendLANAddress                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: formats and sends to the Lantronix card the IP or gateway  */
/*                                                                     */
/* RETURNED VALUE: TRUE if Lantronix card present, FALSE if not        */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

void SendLANAddress( IP_ADDRESS_TYPE  address )
{
U_INT16 count;
U_INT16 subvalue;
volatile BIT8 *pRx_Tx;

   /* Point to the xmit/receive buffers of the LAN port */
   pRx_Tx = Duart_CB[LAN_PORT].pRx_Tx;

   for( count = 0; count <= 3; count++ )
   {
      /* Scan for right parenthesis/space before sending each value */
      /* Abort if timned out */
      if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return;
      subvalue = address.byte[count];
      *pRx_Tx = (BIT8)((subvalue / 100) + '0');
      subvalue = subvalue % 100;
      *pRx_Tx = (BIT8)((subvalue / 10) + '0');
      *pRx_Tx = (BIT8)((subvalue % 10) + '0');
      if( count >= 3 ) break;
      *pRx_Tx = (BIT8)'.';
   }
   *pRx_Tx = (BIT8)13;
}

/***********************************************************************/
/* FUNCTION: ConfigureLAN                                              */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: handles configuration of Lantronix LAN card                */
/*                                                                     */
/* RETURNED VALUE: TRUE if Lantronix card present, FALSE if not        */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

const IP_ADDRESS_TYPE null_address = {0,0,0,0};
const SERIAL_PARMS_TYPE Lantronix_Config_Parms =
{ BR_9600, HS_NONE, PARITY_NONE, STOP_BITS_1, DATA_BITS_8, TERM_SEQ_LF };
const SERIAL_PARMS_TYPE Lantronix_Operating_Serial_Parms =
{ BR_57600, HS_HARDWARE, PARITY_NONE, STOP_BITS_1, DATA_BITS_8, TERM_SEQ_LF };

BIT8 ConfigureLAN(void)
{
volatile BIT8 *pRx_Tx;
U_INT16 attempt;
DUARTBUF_RX_TYPE  *pduartRxbuf_v;
BIT8 count;
U_INT32 mask;

   pduartRxbuf_v = &DuartRxBuf_V[LAN_PORT];

   /* Point to the xmit/receive buffers of the LAN port */
   pRx_Tx = Duart_CB[LAN_PORT].pRx_Tx;


   /* Reset the Lantronix card */
   DuartEnableLANReset();

   /* Set up the serial port for LAN */
   TurnOnDuart(LAN_PORT, Lantronix_Config_Parms);

   /* Allow ~ 1000mSec while it resets */
   Duart_CB[4].Handshake_Timeout = 0;
   while (Duart_CB[4].Handshake_Timeout < 512)
   {
      Task_yield();
   }

   /* Unreset the Lantronix card */
   DuartDisableLANReset();

   /* Send three lower case x characters to */
   /* enter configuration mode */
   /* Don't worry about status as the 16 byte FIFO is empty */
   *pRx_Tx = 'x';
   *pRx_Tx = 'x';
   *pRx_Tx = 'x';

   /* Check every 500 mSec to see if the Lantronix card is responding */
   for( attempt = 1; attempt <= 10; attempt++ )
   {
      Duart_CB[4].Handshake_Timeout = 0;
      while (Duart_CB[4].Handshake_Timeout < 256)
      {
         Task_yield();
      }

      /* see if any characters in the receive buffer */
      if( pduartRxbuf_v->count > 0 )
      {
         /* Something has been received, check it out */
         break;
      }

      /* Send three lower case x characters to */
      /* enter configuration mode */
      /* Don't worry about status as the 16 byte FIFO is empty */
      *pRx_Tx = 'x';
      *pRx_Tx = 'x';
      *pRx_Tx = 'x';
   }

   /* Make sure we are talking to a Lantronix card */
   if( ScanForString( &UDS_LANTRONIX[0] ) == FALSE ) return FALSE;

   /* Now scan for the serial number */
   if( ScanForString( &UDS_SERIAL_NUMBER[0] ) == FALSE ) return FALSE;

   /* Record the serial number */
   count = SaveStringData( &LAN_serial_number[0], ' ', 10 );
   if( (count < 4) || (count > 9) ) return FALSE;

   /* Now scan for the MAC address */
   if( ScanForString( &UDS_MAC_ADDRESS[0] ) == FALSE ) return FALSE;

   /* Record the MAC address */
   count = SaveStringData( &LAN_MAC_address[0], (BIT8)13, 17 );
   if( count != 17 ) return FALSE;

   /* Now scan for the software version */
   if( ScanForString( &UDS_SOFTWARE_VERSION[0] ) == FALSE ) return FALSE;

   /* Record the software version */
   count = SaveStringData( &LAN_software_version[0], (BIT8)0, 14 );
   if( (count < 5) || (count > 15) ) return FALSE;

   /* Now scan for the prompt to enter setup mode */
   if( ScanForString( &UDS_SETUP_MODE[0] ) == FALSE ) return FALSE;

   /* In response to this prompt we send carriage return */
   *pRx_Tx = (BIT8)13;

   /* The Lantronix now sends us its current configuration, which we ignore */
   /* The next prompt from Lantronix is Your Choice ? */
   if( ScanForString( &UDS_YOUR_CHOICE[0] ) == FALSE ) return FALSE;

   /* Our response to this is choice 0 (server configuration) */
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* We are now prompted for the four values that make up the IP address */
   /* Each prompt is the current value surrounded by parentheses, then space */

   /* Send the IP address */
   if (LAN_bootp_mode == TRUE)
   {
      SendLANAddress( null_address );
   }
   else
   {
      SendLANAddress( IP_Address );
   }

   /* Next we are prompted on whether to set a gateway address */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;

   /* answer Y for yes */
   *pRx_Tx = (BIT8)'Y';

   /* Send the gateway address */
   if (LAN_bootp_mode == TRUE)
   {
      SendLANAddress( null_address );
   }
   else
   {
      SendLANAddress( Gateway );
   }

   /* Next we are prompted for the subnet mask */
   /* We must first scan past '(0=default)' to get to the */
   /* right parenthesis after the current value */
   if( ScanForString( &UDS_DEFAULT[0] ) == FALSE ) return FALSE;
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;

   /* Send the subnetmask */
   if (LAN_bootp_mode == TRUE)
   {
      *pRx_Tx = (BIT8)('0');
      *pRx_Tx = (BIT8)('0');
      *pRx_Tx = (BIT8)13;
   }
   else
   {
      mask = Subnet.value;
      count = 32;
      while( mask && count )
      {
         count -= 1;
         mask = mask << 1;
      }
      *pRx_Tx = (BIT8)((count / 10) + '0');
      *pRx_Tx = (BIT8)((count % 10) + '0');
      *pRx_Tx = (BIT8)13;
   }

   /* Next we are prompted to set a telnet configuration password */
   /* We answer Y (yes) and set this to NO PASSWORD */
   /* QUESTION: should we set a password or allow the user to */
   /* set one, or leave alone one that is already set? */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'Y';

   /* By responding CR with no other characters we set the password to none */
   *pRx_Tx = (BIT8)13;

   /* Next there are two possibilities */
   /* We could be prompted for a DHCP device name, or we could go */
   /* straight to "Your choice ?" */
   /* If prompted for device name then we answer with CR */

   switch( ScanForTwoStrings( &UDS_Q_N[0], &UDS_YOUR_CHOICE[0] ))
   {
   case 0:
   default:
      /* Timed out */
      return FALSE;
   case 1:
      /* We were prompted for device name, answer CR and then */
      /* scan for Your Choice ? */
      *pRx_Tx = (BIT8)13;
      if( ScanForString( &UDS_YOUR_CHOICE[0] ) == FALSE ) return FALSE;
      break;
   case 2:
      break;
   }

   /* This time our response to this is choice 1 (channel 1 configuration) */
   *pRx_Tx = (BIT8)'1';
   *pRx_Tx = (BIT8)13;

   /* First we are prompted for baudrate, to which we answer 57600 */
   /* NOTE: several of the prompts that follow have a question mark */
   /* at the end. Even though we do not wait for the question mark */
   /* there should not be a problem since the Lantronix should have */
   /* at least started transmitting it by now, and our response will */
   /* not arrive for a full character transmission time. This is a */
   /* precaution in case Lantronix decides to be more consistent and */
   /* never (or always) include the question mark */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'5';
   *pRx_Tx = (BIT8)'7';
   *pRx_Tx = (BIT8)'6';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* Next we are prompted for I/F (interface) mode */
   /* Our response is 4C, which is 8 data bits, 1 stop bit and no parity */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'4';
   *pRx_Tx = (BIT8)'C';
   *pRx_Tx = (BIT8)13;

   /* Next we are prompted for flow control */
   /* Our response is 00 for no flow control */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'2';
   *pRx_Tx = (BIT8)13;

   /* Next we are prompted for port number */
   /* for now set the port number to 9100 */
   /* QUESTION: do we want this parameter to be user settable? */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'9';
   *pRx_Tx = (BIT8)'1';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* Next we are prompted for connect mode */
   /* Our response is C0, which is accept */
   /* incoming (network) connection unconditionally */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'C';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* We are now prompted for remote IP address, which is a */
   /* don't care for us so we leave it at its current value */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'.';
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'.';
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'.';
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)13;

   /* Remote port we also leave alone */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)13;

   /* Next is disconnect mode, which we set to 00 for Ignore DTR */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* Next is flush mode, which we set to 00 for no flushing */
   /* of buffers and no alternate packing algorithm */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* By disabling alternate packing above, we are not prompted */
   /* for pack control */

   /* Next is disconnect timeout, which we set to 00 minutes and 00 */
   /* seconds to disable timeout due to inactivity on the serial side */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;
   /* the prompt character for seconds is colon */
   if( ScanForString( &UDS_COLON[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* Next is send character 1 - this is used to cause an */
   /* immediate send data when this character is received */
   /* on the serial line. We use line feed (0A) */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'A';
   *pRx_Tx = (BIT8)13;

   /* Send character 2 is not used, so we set it to 00 (null) */
   if( ScanForString( &UDS_RIGHT_PAREN[0] ) == FALSE ) return FALSE;
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)'0';
   *pRx_Tx = (BIT8)13;

   /* Now we get a repeat of the Your Choice ? prompt */
   if( ScanForString( &UDS_YOUR_CHOICE[0] ) == FALSE ) return FALSE;

   /* This time our response to this is choice 9, save and exit */
   *pRx_Tx = (BIT8)'9';
   *pRx_Tx = (BIT8)13;

   /* There is no further response from the Lantronix card, which */
   /* resets itself and restarts with the new settings */

   /* Return TRUE to indicate that the Lantronix card is alive and */
   /* well and should not be reset so that we can access an */
   /* on-board computer in its place */
   return TRUE;

}

/***********************************************************************/
/* FUNCTION: RS232CommandTask                                          */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: handles configuration of Lantronix LAN card, initialization*/
/*          of Uarts, and transferring serial data between buffers     */
/*                                                                     */
/* RETURNED VALUE: does not return                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

void RS232CommandTask(void)
{
U_INT16  chan;
U_INT16  data_status;
BIT8     data;
BIT8     status;
BIT8    *p_start_data;
BIT8    *p_end_data;
DUART_CB_TYPE  *pduart_cb;
DUARTBUF_TX_TYPE  *pduartTxbuf_v;
DUARTBUF_RX_TYPE  *pduartRxbuf_v;
U_INT16  enable_tx_int;
const SERIAL_PARMS_TYPE *Lan_Port_Serial_Parms;

/* configure the Lantronix LAN card if it is present */
if( ConfigureLAN() == FALSE )
{
   /* Reset the Lantronix card */
   DuartEnableLANReset();

   /* Null out the strings that contain info about the card */
   LAN_MAC_address[0] = (BIT8)0;
   LAN_serial_number[0] = (BIT8)0;
   LAN_software_version[0] = (BIT8)0;

   /* Set up the serial port for OBC */
   Lan_Port_Serial_Parms = &On_Board_Computer_Serial_Parms;

}
else
{
   /* Allow ~ 8000mSec while it resets */
   Duart_CB[4].Handshake_Timeout = 0;
   while (Duart_CB[4].Handshake_Timeout < (512*8))
   {
      Task_yield();
   }

   /* Throw away anything else sent by the Lantronix */
   pduartRxbuf_v = &DuartRxBuf_V[LAN_PORT];
   while (pduartRxbuf_v->count > 0)
   {
      INTERRUPTS_OFF;
         GetBufPtr (pduartRxbuf_v, &data_status);
      INTERRUPTS_ON;
   }

   /* Set up the serial port for LAN */
   Lan_Port_Serial_Parms = &Lantronix_Operating_Serial_Parms;

}

/* indicate DataComm testing is complete */
DataComm_Power_On_Complete = TRUE;

/* Wait for the power on test to complete */
while(!(POWER_ON_TEST_COMPLETE))
{
   Task_yield();
}

INTERRUPTS_OFF;
/* Start up communications */
TurnOnDuart(HOST_PORT, Init_Host_Port_Serial_Parms);
TurnOnDuart(LAN_PORT, *Lan_Port_Serial_Parms);
TurnOnDuart(INJECTOR1_PORT, Tower_Port_Parms);
TurnOnDuart(INJECTOR2_PORT, Tower_Port_Parms);
TurnOnDuart(TRAY_PORT, Tray_Port_Parms);
INTERRUPTS_ON;


while (TRUE)                 /* Loop Forever */
{
   for(   chan = DRTA_PORT;  chan <= DRTE_PORT; chan++)
   {
      pduart_cb = &Duart_CB[chan];
      pduartTxbuf_v = &DuartTxBuf_V[chan];
      pduartRxbuf_v = &DuartRxBuf_V[chan];

      while( (pduartRxbuf_v->count > 0) &&
                   (pduart_cb->Waiting_For_Rd_Packet == FALSE) )
      {
         /******************/
         /* Get next input */
         /******************/

         INTERRUPTS_OFF;
            GetBufPtr(pduartRxbuf_v,&data_status);
         INTERRUPTS_ON;
         data = (BIT8)data_status;
         status = (BIT8)(data_status >> 8);
         pduart_cb->Error |= status;


         /********************/
         /* handle handshake */
         /********************/

         switch(Serial_Port_Handshake[chan])
         {
         case HS_XON_XOFF:
            if( (pduart_cb->Rx_XonXoff_State == XOFF_STATE) &&
                           (pduartRxbuf_v->count <= Rx_XON_POINT) )
            {
               pduart_cb->Rx_XonXoff_State = XON_STATE;
               pduart_cb->Rx_Send_XON = TRUE;
               INTERRUPTS_OFF;
                  DuartEnableTxInt(chan);
               INTERRUPTS_ON;
            }
            break;
         case HS_HARDWARE:
            if( (pduart_cb->Rx_XonXoff_State == XOFF_STATE) &&
                           (pduartRxbuf_v->count <= Rx_XON_POINT) )
            {
               pduart_cb->Rx_XonXoff_State = XON_STATE;
               Set_RTS_ON(chan);
            }
            break;
         default:
            /* do nothing */
            break;
         } /* switch */

         /************************/
         /* check buffer overrun */
         /************************/
         if(data_status == DATA_LOSS)
         {
            pduart_cb->Data_Loss = TRUE;
         }

         /**************************/
         /* check for msg from hss */
         /**************************/
         if (((data & 0x7f) == Stx) /* & (chan == TRAY_PORT) */ )
         {
            /* Received StartOfText from the tray port */
            /* Discard anything that came before and */
            /*  substitute 'HSHSHS ' */

            /* Point to the start of the buffer */
            p_start_data = pduart_cb->pRd_Data_Start;

            /* Copy the string into the buffer */
            *p_start_data++ = 'H';
            *p_start_data++ = 'S';
            *p_start_data++ = 'H';
            *p_start_data++ = 'S';
            *p_start_data++ = 'H';
            *p_start_data++ = 'S';
            data            = ' ';

            /* Adjust the data length value */
            pduart_cb->pRd_Packet->data_length = 6;
            /* the seventh character will be added below */

         }

         /************************/
         /* check for end of msg */
         /************************/
         if(data == pduart_cb->Term_Seq)
         {
            /* end of message, so send packet to cmd processor */
            *(pduart_cb->pRd_Data_Start +
               pduart_cb->pRd_Packet->data_length++) = data;
            /* check for errors and indicate end of msg */
            if(pduart_cb->Error & (OV_RUN_ERR | PARITY_ERR | FRAME_ERR))
            {
               if(pduart_cb->Error & (OV_RUN_ERR))
               {
                  /* Receiver over-run error */
                  pduart_cb->pRd_Packet->return_stat = RET_DATA_OVERRUN;
               }
               else
               {
                  /* Parity or framing error */
                  pduart_cb->pRd_Packet->return_stat = RET_DATA_ERR;
               }
            }
            else
            {
               if(pduart_cb->Data_Loss == TRUE)
               {
                  /* data overrun */
                  pduart_cb->pRd_Packet->return_stat = RET_DATA_OVERRUN;
                  pduart_cb->Data_Loss = FALSE;
               }
               else
               /* data OK */
               {
                  pduart_cb->pRd_Packet->return_stat = RET_OK;
               }
            }

            /* reset errors bits from DUART (parity,overrun,framing,break) */
            pduart_cb->Error = 0;

            AppendPacket(pduart_cb->pRd_Packet, Rd_Input_Q);
            SetUpDuartRdPacket(chan);  /* sets  Waiting_For_Rd_Packet */

         }   /* if(data == pduart_cb->Term_Seq */
         else
         {
            /* not term seq */
            /* store input */
            *(pduart_cb->pRd_Data_Start +
               pduart_cb->pRd_Packet->data_length++) = data;
            /* check if this fills packet */
            if (pduart_cb->pRd_Packet->data_length >=
                                  pduart_cb->pRd_Packet->max_data_len)
            {
               /* check for errors and indicate end of msg */
               /*    packet may be full because of errors */
               if(pduart_cb->Error & (OV_RUN_ERR | PARITY_ERR | FRAME_ERR))
               {
                  if(pduart_cb->Error & OV_RUN_ERR)
                  {
                     /* Receiver over-run error */
                     pduart_cb->pRd_Packet->return_stat = RET_DATA_OVERRUN;
                  }
                  else
                  {
                     /* Parity or framing error */
                     pduart_cb->pRd_Packet->return_stat = RET_DATA_ERR;
                  }
               }
               else
               {
                  /* no errors from duart check for input buffer overflow */
                  if(pduart_cb->Data_Loss == TRUE)
                  {
                     /* data overrun */
                     pduart_cb->pRd_Packet->return_stat = RET_DATA_OVERRUN;
                     pduart_cb->Data_Loss = FALSE;
                  }
                  else
                  /* data OK but packet full with no term seq */
                  {
                     /* indicate partial msg */
                     pduart_cb->pRd_Packet->return_stat = RET_PARTIAL_MSG;
                  }
               }
               /* reset errors bits from DUART (parity,overrun,framing,break) */
               pduart_cb->Error = 0;

               /* packet full - ship off this packet and set up new */
               AppendPacket(pduart_cb->pRd_Packet, Rd_Input_Q);
               SetUpDuartRdPacket(chan);   /* sets  Waiting_For_Rd_Packet */
            }
         } /* else */
      }  /* while */


   /*****************/
   /* handle output */
   /*****************/

      enable_tx_int = FALSE;

      pthread_mutex_lock(&Wr_Output_Q_Mut);
      /* if not sending packet and a new packet is avail: setup new packet */
      if((!pduart_cb->Transmitting)&&(Wr_Output_Q[chan].num_entries > 0))
      {
         /* get next packet */
         GetPacket(pduart_cb->pWr_Packet,Wr_Output_Q[chan]);
         /* determine 32 bit address */
         pduart_cb->pWr_Data_Start = pduart_cb->pWr_Transfer =
                    (BIT8 *)DMA_MEM + pduart_cb->pWr_Packet->data_start;

         pduart_cb->Transmitting = TRUE;
      }
      pthread_mutex_unlock(&Wr_Output_Q_Mut);

      /* check if transmitting a packet */
      if(pduart_cb->Transmitting)
      {
         /* find address of last byte of data */
         p_end_data = pduart_cb->pWr_Data_Start +
                               pduart_cb->pWr_Packet->data_length;
         while( (pduart_cb->pWr_Transfer < p_end_data) &&
                        (pduartTxbuf_v->count < DUART_TX_BUF_SIZE) )
         {
            INTERRUPTS_OFF;
               PutBufPtr(pduartTxbuf_v,*pduart_cb->pWr_Transfer);
            INTERRUPTS_ON;
            pduart_cb->pWr_Transfer++;
            enable_tx_int = TRUE;
         }
         if( (pduart_cb->pWr_Transfer == p_end_data) &&
                        (pduartTxbuf_v->count < DUART_TX_BUF_SIZE) )
         /* end of packet buffer */
         {
            /* if this is a complete msg (not partial) send term seq */
            if(pduart_cb->pWr_Packet->cmd_mod == COMPLETE_MSG)
            {
               /* send terminating sequence */
               INTERRUPTS_OFF;
                  PutBufPtr(pduartTxbuf_v,pduart_cb->Term_Seq);
               INTERRUPTS_ON;
               enable_tx_int = TRUE;
            }

            /* return write packet to free list */
            pthread_mutex_lock(&Wr_Free_Q_Mut);
            AppendPacket(pduart_cb->pWr_Packet, Wr_Free_Q);
            pthread_mutex_unlock(&Wr_Free_Q_Mut);
            /* try to get next packet and initialize pointers */
            pthread_mutex_lock(&Wr_Output_Q_Mut);
            GetPacket(pduart_cb->pWr_Packet,Wr_Output_Q[chan]);
            pthread_mutex_unlock(&Wr_Output_Q_Mut);
            /* if more packets - set up next msg else indicate not trans. */
            if(pduart_cb->pWr_Packet != NULL)
            {
               pduart_cb->pWr_Data_Start = pduart_cb->pWr_Transfer =
                  (BIT8 *)DMA_MEM + pduart_cb->pWr_Packet->data_start;
               pduart_cb->Transmitting = TRUE;
            }
            else
            {
               /* no packets available */
               pduart_cb->Transmitting = FALSE;
            }
         }
         if( enable_tx_int == TRUE)
         {
            INTERRUPTS_OFF;
               DuartEnableTxInt(chan);
            INTERRUPTS_ON;
         }
      } /* if((pduart_cb->Transmitting)&& */

   }  /* for */

   /* Check for headspace sampler commands and process them */

   Task_yield();
}  /* while (TRUE)  */
}
